from rlcore import *
from erlgrammar import *

from erlglobals import *

def filterPotentialWeapon( item ):
	getTriggers = getattr( item, "triggers", None)
	if getTriggers and getTriggers():
		return True
	meleeCap = getattr( item.itemType, "meleeCapability", None)
	if meleeCap: return True
	return False

class ItemTypeUnique:
	serializedAttributes = [
		"name",
		"glyph",
		"unit",
		"weight"
	]
	def __init__(self, name, glyph, weight):
		self.name = name
		self.glyph = glyph
		self.unit = None
		self.weight = weight
	def __eq__(self, b):
		return False
	# we don't need spawn() here

class RuntimeItemUnique:
	serializedAttributes = [
		"itemType",
		"amount",
		"glyph",
		"container",
		"x",
		"y",
		"facing",
		"level"
	]
	def __init__(self, name, glyph, weight, fullDescription): # name is Noun
		self.itemType = ItemTypeUnique( name, glyph, weight )
		self.amount = 1
		self.glyph = glyph
		self.container = None
		self.fullDescription = fullDescription
	def take(self, amount):
		if amount > 0:
			if self.container:
				self.container.remove( self )
			self.container = None
			return self
	def description(self):
		return self.fullDescription
	def sameItem(self, that):
		return id(self) == id(that)
	def weight(self):
		return self.itemType.weight
	def commonName(self):
		return self.itemType.name.singular
supportsSerialization( RuntimeItemUnique )

class ItemUnit:
	def __init__(self, name, decimals):
		self.name = name
		self.decimals = decimals
	def describe(self, amount):
		if self.decimals > 0:
			fmt = "%%0.%dlf" % self.decimals
			amt = fmt % (amount / float(10**self.decimals) )
		else:
			amt = str(amount)
		if amt == "1":
			return "1 %s" % self.name.singular
		else:
			return "%s %s" % (amt, self.name.plural)

class Unit:
	weightSmall = ItemUnit( Noun( singular="gram", plural="grams" ), 0 )
	weight = ItemUnit( Noun( singular="kilogram", plural="kilograms" ), 2 )
	length = ItemUnit( Noun( singular="meter", plural="metres" ), 2 )
	volume = ItemUnit( Noun( singular="milliliter", plural="millilitres" ), 0 )

class ItemStack:
	serializedAttributes = [
		"itemType",
		"glyph",
		"amount",
		"container",
		"controller",
		"x",
		"y",
		"facing",
		"level"
	]
	def __init__(self, itemType, amount = 1, container = None):
		self.itemType = itemType
		self.glyph = itemType.glyph # for duck compatibility with old Item (which wasn't even implemented)
		self.amount = amount
		self.container = container # containing inventory
	def absorb(self, that):
		assert self.itemType == that.itemType
		self.amount += that.amount
	def take(self, amount):
		taken = max(0, min( self.amount, amount ))
		if taken <= 0:
			return None
		rv = ItemStack( self.itemType, amount = taken, container = None )
		self.amount -= taken
		if self.amount <= 0 and self.container:
			self.container.remove( self )
		return rv
	def description(self):
		return self.itemType.describe( self.amount )
	def tick(self):
		pass
	def commonName(self):
		return self.itemType.name.singular
	def sameItem(self, that):
		return that.itemType == self.itemType
	def weight(self):
		return self.itemType.weight * self.amount

class ItemType:
	serializedAttributes = [
		"name",
		"unit",
		"glyph",
		"meleeCapability",
		"usable",
		"weight"
	]
	def __init__(self, name, glyph, weight, unit = None, meleeCapability = None, usable = None):
		self.meleeCapability = meleeCapability
		self.name = name
		self.unit = unit # e.g. ItemUnit(Noun(singular="gram",plural="grams",1))
		self.glyph = glyph
		self.usable = usable
		self.weight = weight
	def __repr__(self):
		return "ItemType:%s,#%d" % (self.name.singular, id(self))
	def spawn(self, amount = 1):
		return ItemStack( itemType = self, amount = amount )
	def describe(self, amount):
		if self.unit == None:
			if amount == 0:
				return "no %s" % self.name.plural
			if amount == 1:
				return "%s %s" % (self.name.indefiniteArticle, self.name.singular)
			return "%d %s" % (amount, self.name.plural)
		else:
			if self.unit.decimals > 0:
				fmt = "%%0.%dlf" % self.unit.decimals
				amt = fmt % (amount / float(10**self.unit.decimals) )
			else:
				amt = str(amount)
			if amount == 0:
				amt = "no" #check: works everywhere?
			elif amt != "1":
				u = self.unit.name.plural
				amt = "%s %s of" % (amt, u)
			else:
				u = self.unit.name.singular
				amt = "%s %s of" % (amt, u)
			return "%s %s" % (amt, self.name.singular)
	def __deepcopy__(self, memo):
		return self

def useMedikit( pc, item ):
	item.take(1)
	pc.hp = pc.maxHp
isAllowedPointer( useMedikit )

class Inventory: # not necessarily the player's; basically just a collection of objects
	serializedAttributes = [
		"items",
		"weightLimit",
		"slotLimit",
#		"typeRestriction"
	]
	def __init__(self):
		self.items = {}
		self.weightLimit = None
		self.slotLimit = None
# now done elsewhere #		self.typeRestriction = None
	def totalWeight(self):
		return sum( [ stack.weight() for stack in self.items.values() ] )
	def nextSlot(self):
		keys = self.items.keys()
		countTo = self.slotLimit
		if not countTo: countTo = len(keys) + 1
		for i in range( countTo ):
			if not i in keys:
				return i
		raise NoMoreSlots()
	def add(self, itemStack):
		assert itemStack.container == None
		if self.weightLimit and self.totalWeight() + itemStack.weight() > self.weightLimit:
			weightLeft = self.weightLimit - self.totalWeight()
			amountOkay = weightLeft // itemStack.itemType.weight
			leftoverAmount = itemStack.amount - amountOkay
		else:
			amountOkay = itemStack.amount
			leftoverAmount = 0
		if amountOkay <= 0:
			return itemStack, None
		takenItems = itemStack.take( amountOkay )
		if leftoverAmount > 0:
			print itemStack.itemType
			returned = itemStack.itemType.spawn( leftoverAmount )
		else:
			returned = None
		if not takenItems:
			return returned, None
		takenItems.container = self
		sameItem = self.findType( takenItems.itemType )
		if sameItem:
			sameItem.absorb( takenItems )
			return returned, takenItems
		slot = self.nextSlot()
		assert not self.items.has_key( slot )
		self.items[ slot ] = takenItems
		return returned, takenItems
	def remove(self, itemStack):
		for key in self.items.keys():
			if self.items[key] == itemStack:
				del self.items[key]
	def __getitem__(self, n):
		return self.items.values()[n]
	def __iter__(self):
		return self.items.values().__iter__()
	def __len__(self):
		return len( self.items )
	def findType(self, itemType):
		for item in self.items.values():
			if item.itemType == itemType:
				return item # there should only be one
		return None

class ItemTable:
	Wrench = ItemType( Noun(short=("a","sturdy wrench","sturdy wrenches")), Glyph( '/', (178,178,168) ), meleeCapability=(0.75,wrenchAwesomenessMultiplier*40), weight=200)
	isAllowedPointer( Wrench, "Wrench" )

	MediKit = ItemType( Noun(short=("a","medicinal emergency kit","medicinal emergency kits")), Glyph( '+', (198,0,0), (200,200,200) ), usable=useMedikit, weight=400)
	isAllowedPointer( MediKit, "MediKit" )

	FireGem = ItemType( Noun(short=("a","red lens","red lenses")), Glyph( '0', (200,0,0) ), weight = 10)
	isAllowedPointer( FireGem, "FireGem")
	FreezeGem = ItemType( Noun(short=("a","blue lens","blue lenses")), Glyph( '0', (0,0,200) ), weight = 10)
	isAllowedPointer( FreezeGem, "FreezeGem")
	BrilliantGem = ItemType( Noun(short=("a","white lens","white lenses")), Glyph( '0', (255,255,255) ), weight = 10)
	isAllowedPointer( BrilliantGem, "BrilliantGem")

	Explosive = ItemType( Noun(short=("a","vial of nitroglycerin","vials of nitroglycerin")), Glyph( '!', (200,200,200) ), weight = 20)
	isAllowedPointer( Explosive, "Explosive")

	RandomMisc = [ MediKit ] * 3 + [ Explosive ] * 3 + [ FireGem, BrilliantGem, FreezeGem ]

		# fuel
	Coal = ItemType( Noun(singular="coal"), Glyph( '*', (20,20,20) ), unit=Unit.weight, weight=1)
	isAllowedPointer( Coal, "Coal" )

		# raw materials
	Iron = ItemType( Noun(singular="iron"), Glyph( '=', (140,100,100) ), unit=Unit.weight, weight=1)
	isAllowedPointer( Iron, "Iron" )
	Brass = ItemType( Noun(singular="brass"), Glyph( '=', (0x59,0x26,0x00) ), unit=Unit.weight, weight=1)
	isAllowedPointer( Brass, "Brass" )
	Glass = ItemType( Noun(singular="glass"), Glyph( '=', (0,102,255) ), unit=Unit.weight, weight=1)
	isAllowedPointer( Glass, "Glass" )
	Gold = ItemType( Noun(singular="gold"), Glyph( '=', (0xff,0xd7,0) ), unit=Unit.weight, weight=1)
	isAllowedPointer( Gold, "Gold" )
	StrangeMetal = ItemType( Noun(singular="star-metal"), Glyph( '=', (0xff,0x0,0xab) ), unit=Unit.weight, weight=1)
	isAllowedPointer( StrangeMetal, "StrangeMetal" )

	RandomMaterials = [ Iron, Brass ]

		# misc. resources -- these are randomly needed for a particular design
		#   resources are differentiated from materials in that the hardest part
		#   in gathering the former is finding them, while the more problematic
		#   part of gathering materials is their weight.
	Nut = ItemType( Noun(short=("a","nut","nuts")), Glyph( ',', (128,128,128) ), weight= universalSprocketWeight)
	isAllowedPointer( Nut, "Nut" )
	Bolt = ItemType( Noun(short=("a","bolt","bolts")), Glyph( ',', (128,128,128) ), weight= universalSprocketWeight) 
	isAllowedPointer( Bolt, "Bolt" )
	Gear = ItemType( Noun(short=("a","gear","gears")), Glyph( ',', (128,128,128) ), weight= universalSprocketWeight)
	isAllowedPointer( Gear, "Gear" )
	Valve = ItemType( Noun(short=("a","valve","valves")), Glyph( ',', (128,128,128) ), weight= universalSprocketWeight)
	isAllowedPointer( Valve, "Valve" )
	Sprocket = ItemType( Noun(short=("a","sprocket","sprockets")), Glyph( ',', (128,128,128) ), weight= universalSprocketWeight)
	isAllowedPointer( Sprocket, "Sprocket" )

	RandomResources = [ Nut, Bolt, Gear, Valve, Sprocket ]



class ItemCounter:
	def __init__(self, itemType):
		self.itemType = itemType
	def __call__(self, n, span):
		return self.itemType.describe( n )
